// WindowManager.java
package org.zjx.manager;

import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinDef;
import lombok.extern.slf4j.Slf4j;
import org.zjx.core.IWindow;
import org.zjx.core.impl.GameWindow;
import org.zjx.core.impl.LoginWindow;
import org.zjx.core.impl.StartWindow;
import org.zjx.state.StateManager;
import org.zjx.util.HwndUtil;

import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 窗口管理器 - 修复无限创建和效率问题
 */
@Slf4j
public class WindowManager {
    // 窗口状态常量
    private static final String WINDOW_CLASS_LAUNCHER = "#32770";
    private static final String WINDOW_CLASS_GAME = "WSGAME";
    private static final String GAME_TITLE = "梦幻西游 ONLINE";

    private static final long WINDOW_CREATION_TIMEOUT = 30000;
    private static final long MONITOR_INTERVAL = 5;

    private static volatile WindowManager instance;
    private static final Object instanceLock = new Object();

    private final List<IWindow> managedWindows = Collections.synchronizedList(new ArrayList<>());
    private final int targetWindowCount;
    private final String gameExePath;
    private final ScheduledExecutorService monitorExecutor;
    private final AtomicBoolean isMonitoring = new AtomicBoolean(false);
    private final AtomicBoolean isInitialized = new AtomicBoolean(false);
    private final AtomicInteger windowCreationCounter = new AtomicInteger(0);

    // 新增：创建控制变量
    private final AtomicBoolean isCreatingWindow = new AtomicBoolean(false);
    private final AtomicInteger consecutiveFailures = new AtomicInteger(0);
    private static final int MAX_CONSECUTIVE_FAILURES = 3;

    private WindowManager(int targetWindowCount, String gameExePath) {
        if (targetWindowCount <= 0) {
            throw new IllegalArgumentException("目标窗口数量必须大于0");
        }
        if (gameExePath == null || gameExePath.trim().isEmpty()) {
            throw new IllegalArgumentException("游戏路径不能为空");
        }

        this.targetWindowCount = targetWindowCount;
        this.gameExePath = gameExePath;
        this.monitorExecutor = Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, "WindowMonitor"));

        // 添加关闭钩子
        Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown, "WindowManager-ShutdownHook"));
    }

    public static WindowManager getInstance(int targetWindowCount, String gameExePath) {
        if (instance == null) {
            synchronized (instanceLock) {
                if (instance == null) {
                    instance = new WindowManager(targetWindowCount, gameExePath);
                }
            }
        }
        return instance;
    }

    public static WindowManager getInstance() {
        if (instance == null) {
            throw new IllegalStateException("WindowManager 未初始化，请先调用 getInstance(int targetWindowCount, String gameExePath)");
        }
        return instance;
    }

    /**
     * 转换窗口类型 - LoginWindow 转换为 GameWindow
     */
    public void convertToGameWindow(LoginWindow loginWindow) {
        if (loginWindow == null) {
            log.error("[WindowManager] 转换窗口失败: loginWindow为null");
            return ;
        }

        if (!managedWindows.contains(loginWindow)) {
            log.error("[WindowManager] 转换窗口失败: 窗口不在管理列表中 - {}", loginWindow.getId());
            return ;
        }

        try {
            // 创建新的GameWindow实例（使用相同的HWND）
            GameWindow gameWindow = new GameWindow(loginWindow.getHwnd(),loginWindow.getStateManager());

            // 从管理列表中移除旧的LoginWindow
            managedWindows.remove(loginWindow);

            // 关闭旧的LoginWindow线程
            loginWindow.shutdown();

            // 添加新的GameWindow到管理列表
            managedWindows.add(gameWindow);

            log.info("[WindowManager] 成功转换窗口: {} -> {}", loginWindow.getId(), gameWindow.getId());

        } catch (Exception e) {
            log.error("[WindowManager] 转换窗口失败: {}", loginWindow.getId(), e);
        }
    }

    /**
     * 初始化已存在的窗口
     */
    public void initializeExistingWindows() {
        if (isInitialized.getAndSet(true)) {
            log.info("[WindowManager] 已经初始化过，跳过初始化");
            return;
        }

        log.info("[WindowManager] 开始初始化已存在的窗口");

        // 查找已存在的游戏窗口
        List<WinDef.HWND> existingGameWindows = HwndUtil.findWindows(WINDOW_CLASS_GAME, null);
        log.info("[WindowManager] 发现 {} 个已存在的游戏窗口", existingGameWindows.size());

        int addedCount = 0;
        for (WinDef.HWND hwnd : existingGameWindows) {
            try {
                if (!HwndUtil.haveWindow(hwnd)) {
                    log.debug("[WindowManager] 跳过不可见窗口: {}", hwnd);
                    continue;
                }

                String windowTitle = HwndUtil.getWindowTitle(hwnd);
                IWindow window;

                // 根据窗口标题判断窗口类型
                if (windowTitle != null && !windowTitle.contains("[")) {
                    window = new LoginWindow(hwnd);
                } else {
                    window = new GameWindow(hwnd,new StateManager());
                }

                managedWindows.add(window);
                addedCount++;
                log.info("[WindowManager] 已添加现有窗口: {}", window.getId());

            } catch (Exception e) {
                log.error("[WindowManager] 添加现有窗口失败: {}", hwnd, e);
            }
        }

        log.info("[WindowManager] 初始化完成，成功添加 {} 个窗口，当前窗口数量: {}",
                addedCount, managedWindows.size());
    }

    /**
     * 启动窗口监控
     */
    public void startMonitoring() {
        if (isMonitoring.getAndSet(true)) {
            log.info("[WindowManager] 监控已在运行中");
            return;
        }

        // 确保先初始化已存在的窗口
        if (!isInitialized.get()) {
            initializeExistingWindows();
        }

        log.info("[WindowManager] 开始监控，目标窗口数量: {}，当前窗口数量: {}",
                targetWindowCount, managedWindows.size());

        // 每5秒检查一次窗口数量
        monitorExecutor.scheduleAtFixedRate(this::checkAndMaintainWindows,
                0, MONITOR_INTERVAL, TimeUnit.SECONDS);
    }

    /**
     * 停止窗口监控
     */
    public void stopMonitoring() {
        if (!isMonitoring.getAndSet(false)) {
            return;
        }

        log.info("[WindowManager] 停止监控");
        monitorExecutor.shutdown();

        try {
            if (!monitorExecutor.awaitTermination(5, TimeUnit.SECONDS)) {
                log.warn("[WindowManager] 监控线程未及时终止，强制关闭");
                monitorExecutor.shutdownNow();
            }
        } catch (InterruptedException e) {
            monitorExecutor.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }

    /**
     * 检查并维护窗口数量 - 修复无限创建问题
     */
    private void checkAndMaintainWindows() {
        try {
            // 如果正在创建窗口，跳过本次检查
            if (isCreatingWindow.get()) {
                log.debug("[WindowManager] 正在创建窗口中，跳过本次检查");
                return;
            }

            // 检查连续失败次数
            if (consecutiveFailures.get() >= MAX_CONSECUTIVE_FAILURES) {
                log.warn("[WindowManager] 连续创建失败次数过多({})，暂停创建新窗口", consecutiveFailures.get());
                return;
            }

            // 清理无效窗口
            int beforeCount = managedWindows.size();
            cleanupInvalidWindows();
            int afterCount = managedWindows.size();

            if (beforeCount != afterCount) {
                log.info("[WindowManager] 清理了 {} 个无效窗口，当前有效窗口: {}",
                        beforeCount - afterCount, afterCount);
            }

            int currentCount = managedWindows.size();
            log.debug("[WindowManager] 当前窗口数量: {}/{}", currentCount, targetWindowCount);

            if (currentCount < targetWindowCount) {
                int missingCount = targetWindowCount - currentCount;
                log.info("[WindowManager] 需要创建 {} 个新窗口", missingCount);

                // 串行创建窗口，避免竞价问题
                createNewWindowsSequential(missingCount);
            } else {
                // 重置连续失败计数
                consecutiveFailures.set(0);
            }

        } catch (Exception e) {
            log.error("[WindowManager] 窗口维护错误", e);
        }
    }

    /**
     * 串行创建新窗口 - 避免竞价问题
     */
    private void createNewWindowsSequential(int count) {
        if (!isCreatingWindow.compareAndSet(false, true)) {
            log.debug("[WindowManager] 已有创建任务在进行中");
            return;
        }

        try {
            log.info("[WindowManager] 开始串行创建 {} 个新窗口", count);
            int successCount = 0;

            for (int i = 0; i < count; i++) {
                // 检查是否还需要创建
                if (managedWindows.size() >= targetWindowCount) {
                    log.info("[WindowManager] 已达到目标窗口数量，停止创建");
                    break;
                }

                LoginWindow newWindow = createNewLoginWindow();
                if (newWindow != null) {
                    managedWindows.add(newWindow);
                    successCount++;
                    log.info("[WindowManager] 成功创建窗口: {} ({}/{})",
                            newWindow.getId(), successCount, count);
                    consecutiveFailures.set(0); // 重置失败计数
                } else {
                    consecutiveFailures.incrementAndGet();
                    log.warn("[WindowManager] 创建窗口失败，连续失败次数: {}", consecutiveFailures.get());

                    // 单次失败后等待一段时间再继续
                    if (consecutiveFailures.get() < MAX_CONSECUTIVE_FAILURES) {
                        Thread.sleep(2000);
                    }
                }
            }

            log.info("[WindowManager] 串行创建完成: 成功{}/{}", successCount, count);

        } catch (Exception e) {
            log.error("[WindowManager] 串行创建窗口失败", e);
            consecutiveFailures.incrementAndGet();
        } finally {
            isCreatingWindow.set(false);
        }
    }

    /**
     * 创建新的游戏窗口 - 改进版本
     */
    private LoginWindow createNewLoginWindow() {
        int windowId = windowCreationCounter.incrementAndGet();
        log.info("[WindowManager] 开始创建第 {} 个窗口", windowId);

        try {
            // 首先检查是否已有启动窗口
            WinDef.HWND launchWindow = waitForExistingLaunchWindow();

            if (launchWindow == null) {
                log.info("[WindowManager] 未找到现有启动窗口，创建新的游戏实例");
                if (!startNewGameInstance()) {
                    log.error("[WindowManager] 启动新游戏实例失败");
                    return null;
                }
                launchWindow = waitForWindow(WINDOW_CLASS_LAUNCHER, GAME_TITLE, WINDOW_CREATION_TIMEOUT);
            }

            if (launchWindow == null) {
                log.error("[WindowManager] 无法找到游戏启动窗口");
                return null;
            }

            // 处理启动窗口
            StartWindow startWindow = new StartWindow(launchWindow);
            if (!processStartWindow(startWindow)) {
                log.error("[WindowManager] 处理启动窗口失败");
                return null;
            }

            // 等待游戏主窗口出现
            WinDef.HWND gameWindow = waitForWindow(WINDOW_CLASS_GAME, null, 15000);
            if (gameWindow == null) {
                log.error("[WindowManager] 无法找到游戏主窗口");
                return null;
            }

            // 验证窗口有效性
            if (!isValidGameWindow(gameWindow)) {
                log.error("[WindowManager] 找到的游戏窗口无效");
                return null;
            }

            // 短暂等待窗口稳定
            Thread.sleep(1000);

            LoginWindow loginWindow = new LoginWindow(gameWindow);
            log.info("[WindowManager] 成功创建第 {} 个窗口: {}", windowId, loginWindow.getId());
            return loginWindow;

        } catch (Exception e) {
            log.error("[WindowManager] 创建第 {} 个窗口失败", windowId, e);
            return null;
        }
    }

    /**
     * 等待现有启动窗口
     */
    private WinDef.HWND waitForExistingLaunchWindow() throws InterruptedException {
        return waitForWindow(WINDOW_CLASS_LAUNCHER, GAME_TITLE, 10);
    }

    /**
     * 验证游戏窗口有效性
     */
    private boolean isValidGameWindow(WinDef.HWND hwnd) {
        return HwndUtil.isWindowVisible(hwnd) &&
                HwndUtil.isWindowEnabled(hwnd) &&
                HwndUtil.getWindowRectangle(hwnd).width > 100 &&
                HwndUtil.getWindowRectangle(hwnd).height > 100;
    }

    /**
     * 启动新游戏实例
     */
    private boolean startNewGameInstance() {
        StartWindow tempStartWindow = new StartWindow(new WinDef.HWND(Pointer.NULL));
        boolean activationAcquired = false;

        try {
            activationAcquired = ActivationManager.requestActivation(tempStartWindow);
            if (!activationAcquired) {
                log.warn("[WindowManager] 无法获取激活权，无法启动新游戏");
                return false;
            }

            log.info("[WindowManager] 已获取激活权，开始启动游戏");
            openGameViaExecutable();
            return true;

        } catch (Exception e) {
            log.error("[WindowManager] 启动游戏失败", e);
            return false;
        } finally {
            if (activationAcquired) {
                ActivationManager.releaseActivation(tempStartWindow);
            }
        }
    }

    /**
     * 处理启动窗口
     */
    private boolean processStartWindow(StartWindow startWindow) {
        try {
            startWindow.clickStartButton();
            return true;
        } catch (Exception e) {
            log.error("[WindowManager] 点击启动按钮失败", e);
            return false;
        }
    }

    private void openGameViaExecutable() throws IOException {
        File gameFile = new File(gameExePath);
        if (!gameFile.exists()) {
            throw new IOException("游戏可执行文件不存在: " + gameExePath);
        }

        log.info("[WindowManager] 启动游戏: {}", gameExePath);
        Desktop.getDesktop().open(gameFile);
    }

    private WinDef.HWND waitForWindow(String className, String title, long timeoutMs)
            throws InterruptedException {
        long startTime = System.currentTimeMillis();
        long endTime = startTime + timeoutMs;

        while (System.currentTimeMillis() < endTime) {
            List<WinDef.HWND> windows = HwndUtil.findWindows(className, title);

            for (WinDef.HWND hwnd : windows) {
                if (isNewWindow(hwnd)) {
                    log.info("[WindowManager] 找到新窗口: {}", HwndUtil.getWindowInfo(hwnd));
                    return hwnd;
                }
            }

            Thread.sleep(500); // 增加等待间隔，减少CPU使用

            // 检查中断
            if (Thread.currentThread().isInterrupted()) {
                throw new InterruptedException("等待窗口被中断");
            }
        }

        return null;
    }

    /**
     * 检查是否是新窗口（未被管理）
     */
    private boolean isNewWindow(WinDef.HWND hwnd) {
        synchronized (managedWindows) {
            return managedWindows.stream()
                    .noneMatch(window -> window.getHwnd().equals(hwnd));
        }
    }

    /**
     * 清理无效窗口
     */
    private void cleanupInvalidWindows() {
        synchronized (managedWindows) {
            Iterator<IWindow> iterator = managedWindows.iterator();
            int removedCount = 0;

            while (iterator.hasNext()) {
                IWindow window = iterator.next();
                try {
                    if (!window.isValid()) {
                        log.info("[WindowManager] 移除无效窗口: {}", window.getId());
                        iterator.remove();
                        window.shutdown();
                        removedCount++;
                    }
                } catch (Exception e) {
                    log.error("[WindowManager] 检查窗口有效性失败: {}", window.getId(), e);
                    iterator.remove();
                    removedCount++;
                }
            }

            if (removedCount > 0) {
                log.info("[WindowManager] 清理了 {} 个无效窗口", removedCount);
            }
        }
    }

    /**
     * 获取管理的窗口列表（不可修改的副本）
     */
    public List<IWindow> getManagedWindows() {
        synchronized (managedWindows) {
            return Collections.unmodifiableList(new ArrayList<>(managedWindows));
        }
    }

    /**
     * 关闭管理器
     */
    public void shutdown() {
        log.info("[WindowManager] 开始关闭管理器");

        stopMonitoring();

        // 关闭所有窗口线程
        int closedCount = 0;
        synchronized (managedWindows) {
            for (IWindow window : managedWindows) {
                try {
                    window.shutdown();
                    if (window.awaitTermination(5, TimeUnit.SECONDS)) {
                        closedCount++;
                    }
                } catch (Exception e) {
                    log.error("[WindowManager] 关闭窗口失败: {}", window.getId(), e);
                }
            }
            managedWindows.clear();
        }

        isInitialized.set(false);
        log.info("[WindowManager] 管理器已关闭，成功关闭 {} 个窗口", closedCount);
    }

    @Override
    protected void finalize() throws Throwable {
        try {
            if (isMonitoring.get()) {
                log.warn("[WindowManager] 在finalize时仍在运行，执行紧急关闭");
                shutdown();
            }
        } finally {
            super.finalize();
        }
    }
}